/******************************************************************************
 * @file:    evis.h
 * @purpose: embedded Visuals Core Header
 * @version: V0.01
 * @date:    12. August. 2009
 * @author:  Michael Bubestinger <michael.bubestinger@gmx.at>
 *----------------------------------------------------------------------------
 *
 *          Add License
 *
 ******************************************************************************/

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

#include "evis_conf.h"
#include "evis.h"




/**
 * @fn     evis_screens_new()
 * @brief  Initialize double linked list for the SCREEN definitions
 * @return Head of linked list.
 */
EVIS_SCREEN_T *evis_screens_new()
{
    EVIS_SCREEN_T *list = malloc(sizeof(EVIS_SCREEN_T)); //allocate space
    /*set everything to NULL */
    list->next = NULL;
    list->last = NULL;
    list->priority = 0;
    list->x_pos = 0;
    list->y_pos = 0;
    list->object = NULL;
    list->onscreen = 0;
    return list;
}


/**
 * @fn     evis_screens_add(EVIS_SCREEN_T *list,EVIS_SCREEN_T *element)
 * @brief  Adds a element to the screen sorted by the priority!
 * @param  *list: Pointer to the head of the allocatet screenlist
 * @param  *element: Pointer to the element structure;
 * @return Head of linked list.
 */
EVIS_SCREEN_T *evis_screens_add(EVIS_SCREEN_T *list,EVIS_SCREEN_T *element)
{
    while((list->next != NULL) && (element->priority > list->next->priority)) list = list->next; // Go to correct position
    element->last       = list;
    element->next       = list->next;
    list   ->next       = element;
    while(list->last != NULL) list = list->last;    // Go back to the head
    return list;
}


/**
 * @fn     evis_screens_delete(EVIS_SCREEN_T *list)
 * @brief  Removes an element from the screen
 * @param  *element: Pointer to the element structure;
 * @return Head of linked list.
 */
EVIS_SCREEN_T *evis_screens_delete(EVIS_SCREEN_T *element)
{
    element->last->next = element->next;
    element->next->last = element->last;
    while(element->last != NULL) element = element->last; //Go back to the head
    return element;
}


/**
 * @fn     evis_draw_24_rgb_pixel(uint8_t *framebuffer, uint32_t color, uint16_t x, uint16_t y)
 * @brief  Pixeldrawing for 24bit Framebuffers
 * @param  *framebuffer Pointer to the framebuffer
 * @param  color Color in 0RGB
 * @param  x X Position on the screen
 * @param  y y Position on the screen
 * @return TRUE or FALES.
 */
uint8_t evis_draw_24_rgb_pixel(uint8_t *framebuffer, uint32_t color, uint16_t x, uint16_t y)
{
    uint8_t *fb_pos;

    if((y * x) > ( WINDOWSIZE_X * WINDOWSIZE_Y)) /* try to draw outside of the Framebuffer? */
        {
            return FALSE;
        }

    /* Calculate offset for framebuffer WINDOWSIZE_X * 3(BYTEPERPIXEL) * y + 3(BYTEPERPIXEL) * x) */
    fb_pos = (uint8_t *) (framebuffer + (WINDOWSIZE_X * 3 * y) + (x * 3));

    fb_pos[0] = (uint8_t) ((color & 0x00FF0000) >> 16 );  /* R */;
    fb_pos[1] = (uint8_t) ((color & 0x0000FF00) >>  8 );  /* G */;
    fb_pos[2] = (uint8_t)  (color & 0x000000FF);          /* B */;

    return TRUE;
}



uint8_t evis_draw_bmp(uint8_t *framebuffer, uint8_t *sprite, uint16_t x, uint16_t y,uint16_t x_size, uint16_t y_size)
{
    uint8_t  rgb[3];
    uint32_t color;
    uint16_t line,x_pos;

    sprite = sprite + (x_size*y_size*3);
    sprite--;

    for(line = 0; line < y_size; line++)
        {
        /* Increment X Coords for drawing */
        for(x_pos = x_size; x_pos > 0; x_pos--)
            {
            /* Get color */
            rgb[2] = *sprite;
            sprite--;
            rgb[1] = *sprite;
            sprite--;
            rgb[0] = *sprite;
            sprite--;
            color = ((rgb[0] << 16) | (rgb[1] << 8) | rgb[2]);
            /* If outside of the framebuffer return FALSE */
            if(!EVIS_DRAWPIXEL((uint8_t*) framebuffer, color, (x + x_pos), (y + line)))
                {
                    return FALSE;
                }
            }
        }
    return TRUE;
}



void evis_render(uint8_t *fb, EVIS_SCREEN_T *screen)
{
    while((screen = screen->next) != NULL)
        {
            (*(EVIS_DRAW_FP*)(screen->object))(fb,screen);
        }
}


int *evis_draw_obj_img(uint8_t *fb, EVIS_SCREEN_T *screen)
{
    EVIS_SCREEN_T *element;
    EVIS_OBJ_IMG_T *img;
    EVIS_SPRITE_T *spritedesc;

    element    = (EVIS_SCREEN_T *) screen;
    img = (EVIS_OBJ_IMG_T *) element->object;
    spritedesc = (EVIS_SPRITE_T *) img->sprite;

    EVIS_DRAWSPRITE((uint8_t*) fb, spritedesc->sprite, element->x_pos, element->y_pos, spritedesc->size_x, spritedesc->size_y);
    return 0;
}

